﻿using System.Diagnostics.Contracts;
using System.IO;
using OpenLS.Spreadsheet.Formats.Biff.Records;

namespace OpenLS.Spreadsheet.Formats.Biff.OfficeArt
{
    internal struct OfficeArtRecordHeader
    {
        private ushort _recVerrecInstance;
        internal RecType recType;
        internal uint recLen;

        public ushort recInstance
        {
            get { return (ushort) (this._recVerrecInstance >> 4); }
            set
            {
                Contract.Ensures(recInstance == value);
                Contract.Ensures(recVer == Contract.OldValue(recVer));
                _recVerrecInstance = CreateRecVerRecInstance(recVer, value);
            }
        }

        public byte recVer
        {
            get { return (byte) (this._recVerrecInstance & 0xf); }
            set
            {
                Contract.Ensures(recVer == value);
                Contract.Ensures(recInstance == Contract.OldValue(recInstance));
                _recVerrecInstance = CreateRecVerRecInstance(value, recInstance);
            }
        }

        private ushort CreateRecVerRecInstance(byte ver, ushort instance)
        {
            return (ushort) ((ver & 0xf) | (instance << 4));
        }


        public static int ByteLength
        {
            get { return 8; }
        }

        public void Read(BinaryReader reader)
        {
            Contract.Ensures(reader.BaseStream.Position == Contract.OldValue(reader.BaseStream.Position) + ByteLength);
#if DEBUG
            ReadWriteChecker.CheckStruct((ref OfficeArtRecordHeader t, BinaryReader r) => t.Read(r),
                                         (ref OfficeArtRecordHeader t, BinaryWriter w) => t.Write(w), reader, ref this);
#endif
            this._recVerrecInstance = reader.ReadUInt16();
            Contract.Assert((this.recVer | (recInstance << 4)) == this._recVerrecInstance);
            this.recType = (RecType) reader.ReadUInt16();
            this.recLen = reader.ReadUInt32();
        }

        public void Write(BinaryWriter writer)
        {
            writer.Write(_recVerrecInstance);
            writer.Write((ushort)recType);
            writer.Write(recLen);
        }

        public static RecType? Peek(OfficeArtReadContext context)
        {
            return Peek(context.Reader);
        }
        public static RecType? Peek(BinaryReader reader)
        {
            Contract.Ensures(Contract.OldValue(reader.BaseStream.Position) == reader.BaseStream.Position);
            var position = reader.BaseStream.Position;
            if (position == reader.BaseStream.Length)
                return null;
            OfficeArtRecordHeader header = new OfficeArtRecordHeader();
            header.Read(reader);
            reader.BaseStream.Position = position;
            return header.recType;

        }
    }
}